﻿using System;
using System.Collections.Generic;
using NUnit.Framework;
using starLiGHT.Collections;
using Microsoft.Xna.Framework;

namespace starLiGHT.Engine.Tests
{
    [TestFixture]
    public class FastList
    {
        FastList<int> fastList;

        [SetUp]
        public void Init()
        {
            fastList = new FastList<int>();
        }

        [Test]
        public void Constructor01()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4 });

            int[] result = fastList.ToArray();
            Array.Sort(result);

            for (int i = 0; i < 5; i++)
            {
                Assert.AreEqual(i, result[i]);
            }
        }

        [Test]
        public void Insert01()
        {
            for (int i = 0; i < 10; i++)
            {
                fastList.Add(i);
            }

            Assert.AreEqual(10, fastList.Count);
            for (int i = 0; i < 10; i++)
            {
                Assert.AreEqual(i, fastList[i]);
            }

            fastList.Insert(5, 99);
            Assert.AreEqual(11, fastList.Count);
            Assert.AreEqual(4, fastList[4]);
            Assert.AreEqual(99, fastList[5]);
            for (int i = 6; i < 11; i++)
            {
                Assert.AreEqual(i - 1, fastList[i]);
            }
        }

        [Test]
        public void Add01()
        {
            for (int i = 0; i < 10; i++)
            {
                fastList.Add(i);
            }

            Assert.AreEqual(10, fastList.Count);
        }

        [Test]
        public void Add02()
        {
            for (int i = 0; i < 10; i++)
            {
                int refInt = i;
                fastList.Add(ref refInt);
            }

            Assert.AreEqual(10, fastList.Count);
        }

        [Test]
        public void Add03()
        {
            for (int i = 0; i < 10; i++)
            {
                fastList.Add(i);
            }

            int[] results = fastList.GetBuffer();

            for (int j = 0; j < 10; j++)
            {
                Assert.AreEqual(j, results[j]);
            }
        }

        [Test]
        public void Clear01()
        {
            for (int i = 0; i < 50; i++)
            {
                fastList.Add(i);
            }

            fastList.Clear();

            Assert.AreEqual(0, fastList.Count);
        }

        [Test]
        public void GrowBuffer01()
        {
            fastList = new FastList<int>(10);

            for (int i = 0; i < 100; i++)
            {
                fastList.Add(i);
            }

            int[] results = fastList.GetBuffer();

            for (int j = 0; j < 100; j++)
            {
                Assert.AreEqual(j, results[j]);
            }
        }

        [Test]
        public void GrowBuffer02()
        {
            fastList = new FastList<int>(10);

            for (int i = 0; i < 100; i++)
            {
                int intRef = i;
                fastList.Add(ref intRef);
            }

            int[] results = fastList.GetBuffer();

            for (int j = 0; j < 100; j++)
            {
                Assert.AreEqual(j, results[j]);
            }
        }

        [Test]
        public void RemoveAt01()
        {
            for (int i = 0; i < 10; i++)
            {
                fastList.Add(i);
            }

            for (int j = 0; j < 5; j++)
            {
                fastList.RemoveAt(fastList.Count - 1);
            }

            Assert.AreEqual(5, fastList.Count);

            int[] results = fastList.ToArray();
            Array.Sort(results);

            for (int k = 0; k < 5; k++)
            {
                Assert.AreEqual(k, results[k]);
            }
        }

        [Test]
        public void RemoveAt02()
        {
            for (int i = 0; i < 10; i++)
            {
                fastList.Add(i);
            }

            for (int j = 0; j < 5; j++)
            {
                fastList.RemoveAt(j);
            }

            Assert.AreEqual(5, fastList.Count);

            int[] results = fastList.ToArray();
            Array.Sort(results);

            for (int k = 0; k < 5; k++)
            {
                Assert.AreEqual(k + 5, results[k]);
            }
        }

        [Test]
        [ExpectedException("System.IndexOutOfRangeException")]
        public void RemoveAt03()
        {
            for (int i = 0; i < 5; i++)
            {
                fastList.Add(i);
            }

            Assert.AreEqual(5, fastList.Count);

            fastList.RemoveAt(0);
            Assert.AreEqual(4, fastList.Count);

            //TODO: Assert.Throws<System.IndexOutOfRangeException>(fastList.RemoveAt(5));
            fastList.RemoveAt(5);
        }

        [Test]
        public void TryPopFront01()
        {
            int res;

            for (int i = 0; i < 5; i++)
            {
                fastList.Add(i);
            }

            for (int i = 0; i < 5; i++)
            {
                Assert.IsTrue(fastList.TryPopFront(out res));
            }

            Assert.IsFalse(fastList.TryPopFront(out res));
        }

        [Test]
        public void Enumerator01()
        {
            for (int i = 0; i < 10; i++)
            {
                fastList.Add(i);
            }

            int index = 0;
            foreach (int val in fastList)
            {
                Assert.AreEqual(index++, val);
            }
        }

        [Test]
        public void Enumerator02()
        {
            var l = new FastList<int>(new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 });

            using (var e = l.GetEnumerator())
            {
                while (e.MoveNext())
                {
                    if ((e.Current % 2) == 0)
                        e.RemoveCurrent();
                }
            }

            Assert.AreEqual(
                new int[] { 1, 9, 3, 7, 5 },
                l.ToArray()
            );
        }

        [Test]
        public void Enumerator03()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

            using (var e = fastList.GetEnumerator())
            {
                for (int j = 0; j < 2; j++)
                {
                    for (int i = 0; i < 5; i++)
                    {
                        int val;
                        e.GetNext(out val);
                        Assert.AreEqual(i, val);
                    }
                    e.Reset();
                }
            }
        }

        [Test]
        public void Enumerator04()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4 });

            using (var e = fastList.GetEnumerator())
            {
                for (int i = 0; i < 5; i++)
                {
                    int val = 99;
                    e.MoveNext();
                    e.SetCurrent(ref val);
                }
                e.Reset();

                for (int i = 0; i < 5; i++)
                {
                    e.MoveNext();
                    object x = ((System.Collections.IEnumerator)e).Current;
                    Assert.AreEqual(99, (int)x);
                }

                int val2;
                Assert.AreEqual(false, e.GetNext(out val2));
            }
        }

        [Test]
        public void Enumerator05()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

            var l = (System.Collections.IEnumerable)fastList;

            for (int j = 0; j < 2; j++)
            {
                System.Collections.IEnumerator e = l.GetEnumerator();
                for (int i = 0; i < 5; i++)
                {
                    e.MoveNext();
                    Assert.AreEqual(i, e.Current);
                }
                e.Reset();
            }
        }

        [Test]
        public void Enumerator06()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 });

            var l = (System.Collections.Generic.IEnumerable<int>)fastList;

            for (int j = 0; j < 2; j++)
            {
                System.Collections.Generic.IEnumerator<int> e = l.GetEnumerator();
                for (int i = 0; i < 5; i++)
                {
                    e.MoveNext();
                    Assert.AreEqual(i, e.Current);
                }
                e.Reset();
            }
        }

        [Test]
        public void Indexer01()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4, 5 });

            for (int i = 0; i < 6; i++)
            {
                Assert.AreEqual(i, fastList[i]);
            }
        }

        [Test]
        public void Remove01()
        {
            fastList = new FastList<int>(new int[] { 0, 1, 2, 3, 4, 5 });

            Assert.AreEqual(6, fastList.Count);

            fastList.Remove(5);

            Assert.AreEqual(5, fastList.Count);

            for (int i = 0; i < 5; i++)
            {
                Assert.AreEqual(i, fastList[i]);
            }

            for (int i = 0; i < 4; i++)
            {
                fastList.Remove(i);
            }

            Assert.AreEqual(4, fastList[0]);

        }
    }
}
